package com.market.plus.core.mapping.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.googlecode.simpleobjectassembler.ObjectAssembler;
import com.googlecode.simpleobjectassembler.beans.FallbackPropertyAccessor;
import com.market.plus.core.dao.ContentFileDao;
import com.market.plus.core.domain.Album;
import com.market.plus.core.domain.Comment;
import com.market.plus.core.domain.ContentFile;
import com.market.plus.core.domain.News;
import com.market.plus.core.domain.Participant;
import com.market.plus.core.domain.Persistable;
import com.market.plus.core.domain.Relationship;
import com.market.plus.core.domain.Tribe;
import com.market.plus.core.dto.AlbumDto;
import com.market.plus.core.dto.CommentDto;
import com.market.plus.core.dto.ContentFileDto;
import com.market.plus.core.dto.NewsDto;
import com.market.plus.core.dto.ParticipantDto;
import com.market.plus.core.dto.RelationshipDto;
import com.market.plus.core.dto.TribeDto;
import com.market.plus.core.mapping.AlbumTypeToIntegerConvert;
import com.market.plus.core.mapping.DomainService;
import com.market.plus.core.mapping.IDMapping;
import com.market.plus.core.mapping.IntegerToAlbumTypeConvert;
import com.market.plus.core.mapping.IntegerToLockstatusConvert;
import com.market.plus.core.mapping.IntegerToNewsTypeConvert;
import com.market.plus.core.mapping.IntegerToStatusConvert;
import com.market.plus.core.mapping.LockstatusToIntegerConvert;
import com.market.plus.core.mapping.MappingConfigure;
import com.market.plus.core.mapping.NewsTypeToIntegerConvert;
import com.market.plus.core.mapping.StatusToIntegerConvert;

@Service("marketDomainService")
public class DomainServiceImpl implements DomainService {

   private ObjectAssembler objectAssembler;

   private MappingConfigure mappingConfigure;

   private ContentFileDao contentFileDao;

   @Autowired
   public DomainServiceImpl(@Qualifier("marketObjectAssembler") CustomObjectAssembler objectAssembler,
         @Qualifier("marketMappingConfigure") MappingConfigure mappingConfigure,
         @Qualifier("contentFileDao")ContentFileDao contentFileDao) {
      this.objectAssembler = objectAssembler;
      this.mappingConfigure = mappingConfigure;
      this.contentFileDao = contentFileDao;
      objectAssembler.registerCustomConverter(new IntegerToAlbumTypeConvert());
      objectAssembler.registerCustomConverter(new IntegerToNewsTypeConvert());
      objectAssembler.registerCustomConverter(new IntegerToStatusConvert());
      objectAssembler.registerCustomConverter(new IntegerToLockstatusConvert());
      objectAssembler.registerCustomConverter(new LockstatusToIntegerConvert());
      objectAssembler.registerCustomConverter(new AlbumTypeToIntegerConvert());
      objectAssembler.registerCustomConverter(new NewsTypeToIntegerConvert());
      objectAssembler.registerCustomConverter(new StatusToIntegerConvert());
   }

   public <T extends Persistable> List<T> convertTypeCollection(List<?> objectDtos, Class<T> destinationObject,
         String parentPropertyName, Object parent, String... ignoreProperties) {
      List<T> properties = new ArrayList<T>();
      for (Object sourceObject : objectDtos) {
         T objectT = this.objectAssembler.assemble(sourceObject, destinationObject, ignoreProperties);
         PropertyAccessor destinationPropertyAccessor = new FallbackPropertyAccessor(objectT);
         destinationPropertyAccessor.setPropertyValue(parentPropertyName, parent);
         properties.add(objectT);
      }
      return properties;
   }

   public Participant convertParticipant(ParticipantDto participantDto) {
      Participant participant = this.objectAssembler.assemble(participantDto, Participant.class);
      return participant;
   }

   public News convertNews(NewsDto newsdto) {
      String[] excludeProperties = mappingConfigure.getPropertiesExcluding(IDMapping.NEWS_LIMIT);
      List<String> excludePropertiesList = new ArrayList<String>(Arrays.asList(excludeProperties));
      excludePropertiesList.add("contentFiles");
      String[] expectedExcludeProperties =  excludePropertiesList.toArray(new String[]{});
      News news = this.objectAssembler.assemble(newsdto, News.class, expectedExcludeProperties);
      List<ContentFileDto> contentFileDtos = newsdto.getContentFiles();
      List<String> contentFileGUIDs = new ArrayList<String>();
      if(contentFileDtos != null){
         for (ContentFileDto contentFileDto : contentFileDtos){
            contentFileGUIDs.add(contentFileDto.getGuid());
         }
      List<ContentFile> contentFiles = this.contentFileDao.findByGUIDs(contentFileGUIDs);
      news.setContentFiles(contentFiles);
      }
      return news;
   }

   public Album convertAlbum(AlbumDto albumDto) {
      Album album = this.objectAssembler.assemble(albumDto, Album.class);
      return album;
   }

   public Tribe convertTribe(TribeDto tribeDto) {
      Tribe tribe = this.objectAssembler.assemble(tribeDto, Tribe.class);
      return tribe;
   }

   public Comment convertComment(CommentDto commentDto) {
      Comment comment = this.objectAssembler.assemble(commentDto, Comment.class);
      return comment;
   }

   public Relationship convertRelationship(RelationshipDto relationshipDto) {
      Relationship relationship = this.objectAssembler.assemble(relationshipDto, Relationship.class);
      return relationship;
   }
}
